package com.basic.ui.view.image

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.TextUtils
import android.util.AttributeSet
import android.util.Log
import androidx.annotation.*
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.AppCompatImageView
import com.basic.ui.view.image.monitor.ImageMonitor
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.Option
import com.bumptech.glide.load.Transformation
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.load.resource.gif.GifDrawable
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import java.io.File

/**
 * @author Peter Liu
 * @since 2023/7/21 23:02
 *
 */

open class BasicImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
    var isFade = false //是否渐显
    var fadeTime = 0 //渐显时间，默认CROSS_FADE_TIME
    var placeHolder: Drawable? = null//占位图
    var errorDrawable: Drawable? = null//加载失败图
    private var errorUrl: String? = null //加载失败时加载的图片URL
    val overrideSize: Pair<Int, Int>? = null
    private var format8888 = false

    private var requestListeners: MutableList<RequestListener<Drawable>>? = ArrayList()
    private val requestOptions: RequestOptions by lazy { RequestOptions() }
    private val mClipPaint: Paint
    private val mMode: PorterDuffXfermode
    private var loopCountListener: RequestListener<Drawable>? = null
    private var loopCount = 0

    init {
        mClipPaint = Paint()
        mClipPaint.isAntiAlias = true
        mMode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
    }

    /**
     * 开始通过glide加载图片
     */
    @SuppressLint("CheckResult")
    private fun startLoadImage(glideRequest: GlideRequest<Drawable>, model: Any?) {
        //size
        if (overrideSize != null) {
            requestOptions.override(overrideSize.first, overrideSize.first)
        }
        glideRequest.apply(requestOptions)
        //placeholder
        if (placeHolder != null) {
            glideRequest.placeholder(placeHolder)
        }
        //error
        if (!TextUtils.isEmpty(errorUrl)) {
            glideRequest.error(GlideApp.with(this).load(errorUrl))
        } else if (errorDrawable != null) {
            glideRequest.error(errorDrawable)
        }
        //fade
        if (isFade) {
            glideRequest.transition(DrawableTransitionOptions.withCrossFade(fadeTime))
        }
        //listener
        if (!requestListeners!!.isEmpty()) {
            for (listener in requestListeners!!) {
                glideRequest.addListener(listener)
            }
        }
        ImageMonitor.checkDebugMonitorState(glideRequest, this)
        if (format8888) {
            glideRequest.format(DecodeFormat.PREFER_ARGB_8888)
        }
        glideRequest.into(this)
    }

    fun load(string: String?) {
        startLoadImage(GlideApp.with(this).load(string), string)
    }

    fun load(drawable: Drawable?) {
        startLoadImage(GlideApp.with(this).load(drawable), drawable)
    }

    fun load(@RawRes @DrawableRes id: Int?) {
        var model: Any? = id
        try {
            if (id != null) {
                model = resources.getResourceTypeName(id)
                val drawable = AppCompatResources.getDrawable(this.context, id)
                if (drawable is GifDrawable) {
                    model = resources.getResourceTypeName(id) + ".gif"
                }
            }
        } catch (e: Exception) {
            Log.i(TAG, "can not get resourceName from id")
        }
        startLoadImage(GlideApp.with(this).load(id), model)
    }

    fun load(file: File?) {
        startLoadImage(GlideApp.with(this).load(file), file)
    }

    fun load(uri: Uri?) {
        startLoadImage(GlideApp.with(this).load(uri), uri)
    }

    fun load(o: Any?) {
        startLoadImage(GlideApp.with(this).load(o), o)
    }

    @SuppressLint("CheckResult")
    @CheckResult
    fun listener(listener: RequestListener<Drawable>): BasicImageView {
        requestListeners = null
        if (loopCount > 0) {
            setLoopCount(loopCount)
        }
        return addListener(listener)
    }

    @SuppressLint("CheckResult")
    @CheckResult
    fun addListener(listener: RequestListener<Drawable>): BasicImageView {
        if (requestListeners == null) {
            requestListeners = ArrayList()
        }
        requestListeners!!.add(listener)
        return this
    }

    @CheckResult
    fun setLoopCount(loopCount: Int): BasicImageView {
        if (requestListeners == null) {
            requestListeners = ArrayList()
        }
        if (this.loopCount == loopCount && loopCountListener != null && requestListeners!!.contains(
                loopCountListener!!
            )
        ) {
            return this
        }
        this.loopCount = loopCount
        if (loopCountListener != null) {
            requestListeners!!.remove(loopCountListener!!)
        }
        addLoopListener(loopCount)
        return this
    }

    private fun addLoopListener(loopCount: Int) {
        loopCountListener = object : RequestListener<Drawable> {
            override fun onLoadFailed(
                e: GlideException?,
                model: Any,
                target: Target<Drawable>,
                isFirstResource: Boolean
            ): Boolean {
                return false
            }

            override fun onResourceReady(
                resource: Drawable,
                model: Any,
                target: Target<Drawable>,
                dataSource: DataSource,
                isFirstResource: Boolean
            ): Boolean {
                if (resource is GifDrawable) {
                    val gifDrawable = resource
                    gifDrawable.setLoopCount(loopCount)
                    gifDrawable.start()
                }
                return false
            }
        }
        requestListeners!!.add(loopCountListener!!)
    }

    @SuppressLint("CheckResult")
    fun <T> addOption(option: Option<T>, value: T): BasicImageView {
        requestOptions.set(option, value)
        return this
    }

    @SuppressLint("CheckResult")
    fun diskCacheStrategy(strategy: DiskCacheStrategy): BasicImageView {
        requestOptions.diskCacheStrategy(strategy)
        return this
    }

    @SuppressLint("CheckResult")
    fun priority(priority: Priority): BasicImageView {
        requestOptions.priority(priority)
        return this
    }

    @SuppressLint("CheckResult")
    fun transformation(transformation: Transformation<Bitmap?>): BasicImageView {
        requestOptions.transform(transformation)
        return this
    }

    @SuppressLint("CheckResult")
    fun transformations(vararg transformations: Transformation<Bitmap?>): BasicImageView {
        requestOptions.transforms(*transformations)
        return this
    }

    @SuppressLint("CheckResult")
    fun skipMemoryCache(skip: Boolean): BasicImageView {
        requestOptions.skipMemoryCache(skip)
        return this
    }

    @SuppressLint("CheckResult")
    fun centerCrop(): BasicImageView {
        requestOptions.centerCrop()
        return this
    }

    @SuppressLint("CheckResult")
    fun fitCenter(): BasicImageView {
        requestOptions.fitCenter()
        return this
    }

    companion object {
        private const val TAG = "BasicImageView"
        private const val CROSS_FADE_TIME = 500
    }
}